﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BSDS.Core.Data.Local.Jobs;
using BSDS.Core.Model.Services.Jobs.Core;

namespace BSDS.Core.Model.Services.Jobs
{
    public class JobRepository
    {
        private const string CurrentJobsDirectoryName = "jobs_pending";
        private const string ProcessedJobsDirectryName = "jobs_processed";

        private readonly GeocodeJobSerializer geocodeSerializer;
        private readonly UploadJobSerializer uploadSerializer;
        private readonly DownloadJobSerializer downloadSerializer;

        private DirectoryInfo currentJobsDirectory;
        private DirectoryInfo processedJobsDirectory;

        public JobRepository(GeocodeJobSerializer geocodeSerializer, UploadJobSerializer uploadSerializer,
            DownloadJobSerializer downloadSerializer)
        {
            this.geocodeSerializer = geocodeSerializer;
            this.uploadSerializer = uploadSerializer;
            this.downloadSerializer = downloadSerializer;
        }

        public void Initialize()
        {
            currentJobsDirectory = new DirectoryInfo(CurrentJobsDirectoryName);
            processedJobsDirectory = new DirectoryInfo(ProcessedJobsDirectryName);

            if (!currentJobsDirectory.Exists)
            {
                currentJobsDirectory.Create();
            }

            if (!processedJobsDirectory.Exists)
            {
                processedJobsDirectory.Create();
            }
        }

        public void Save(GeocodeJob job)
        {
            var jobFilename = CreateJobFileName(job);

            geocodeSerializer.Serialize(job, jobFilename);
        }
 
        public void Save(UploadJob job)
        {
            var jobFilename = CreateJobFileName(job);
            
            uploadSerializer.Serialize(job, jobFilename);
        }

        public void Save(DownloadJob job)
        {
            var jobFilename = CreateJobFileName(job);

            downloadSerializer.Serialize(job, jobFilename);
        }


        public T Get<T>(string jobId) where T : Job
        {
            var jobFilename = FindFileByJobId(jobId);

            if (typeof(T) == typeof(GeocodeJob))
            {
                return geocodeSerializer.Deserialize(jobFilename) as T;
            }
            
            if (typeof(T) == typeof(DownloadJob))
            {
                return downloadSerializer.Deserialize(jobFilename) as T;
            }
            
            return uploadSerializer.Deserialize(jobFilename) as T;
        }

        public bool Exists(string jobId, string type)
        {
            var jobFilename = FindFileByJobId(jobId);

            return !string.IsNullOrEmpty(jobFilename) && jobFilename.EndsWith(type + ".job");
        }

        private string FindFileByJobId(string jobId)
        {
            foreach (var file in currentJobsDirectory.GetFiles())
            {
                if (file.Name.StartsWith(jobId))
                {
                    return file.FullName;
                }
            }

            throw new ArgumentException("No such job in current jobs queue. Job id " + jobId);
        }

        private string CreateJobFileName(Job job)
        {
            const string filenameTemplate = "{0}_{1}.job";

            var fileName = string.Format(filenameTemplate, job.Id, job.JobTypeName);
            var filePath = Path.Combine(currentJobsDirectory.FullName, fileName);

            return filePath;
        }

        public IEnumerable<GeocodeJob> GetAllGeocodeJobs()
        {
            var searchPattern = string.Format("*{0}.job", GeocodeJob.TypeName);
            var jobFileNames = currentJobsDirectory.GetFiles(searchPattern);

            return jobFileNames.Select(jobFile => geocodeSerializer.Deserialize(jobFile.FullName)).ToList();
        }

        public IEnumerable<UploadJob> GetAllUploadJobs()
        {
            var searchPattern = string.Format("*{0}.job", UploadJob.TypeName);
            var jobFileNames = currentJobsDirectory.GetFiles(searchPattern);

            return jobFileNames.Select(jobFile => uploadSerializer.Deserialize(jobFile.FullName)).ToList();
        }

        public IEnumerable<DownloadJob> GetAllDownloadJobs()
        {
            var searchPattern = string.Format("*{0}.job", DownloadJob.TypeName);
            var jobFileNames = currentJobsDirectory.GetFiles(searchPattern);

            return jobFileNames.Select(jobFile => downloadSerializer.Deserialize(jobFile.FullName)).ToList();
        }

        public void CleanUp(string jobId)
        {
            var jobFilename = FindFileByJobId(jobId);
            var jobFile = new FileInfo(jobFilename);
            var jobDestinationPath = Path.Combine(processedJobsDirectory.FullName, jobFile.Name);

            if (File.Exists(jobDestinationPath))
            {
                File.Delete(jobDestinationPath);
            }

            jobFile.MoveTo(jobDestinationPath);
        }
    }
}